package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.domain.Elder;
import com.zzyl.nursing.domain.FamilyMemberElder;
import com.zzyl.nursing.dto.BindElderDto;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.dto.QueryIoTDataDto;
import com.zzyl.nursing.mapper.MemberUserMapper;
import com.zzyl.nursing.service.IDeviceDataService;
import com.zzyl.nursing.service.IElderService;
import com.zzyl.nursing.service.MemberUserService;
import com.zzyl.nursing.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @Author xiqi
 */
@Service
public class MemberUserServiceImpl extends ServiceImpl<MemberUserMapper, FamilyMemberElder> implements MemberUserService {
    /**
     * 客户绑定老人,将老人的基本信息保存到老人与家属表的中间表
     *
     * @param dto
     */
    @Autowired
    private MemberUserMapper memberUserMapper;
    @Autowired
    private IElderService elderService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IDeviceDataService deviceDataService;
    @Override
    public void bindElder(BindElderDto dto) {
        //前端的请求参数"idCard":老人身份证号 "name": "",老人姓名 "remark": ""称呼
        //1.根据dto中的老人身份证号和老人姓名查询老人id
        Elder elder = elderService.lambdaQuery().eq(Elder::getIdCardNo, dto.getIdCard())
                .eq(Elder::getName, dto.getName())
                .one();
        if (elder==null) {
            throw new RuntimeException("老人不存在或输入的老人姓名及身份证号码有误");
        }
        Long elderId=elder.getId();
        //2.直接从UserThreadLocal中获取id
        Long userId = UserThreadLocal.getUserId();
        //3.封装数据
        FamilyMemberElder familyMemberElder = new FamilyMemberElder();
        familyMemberElder.setElderId(elderId);
        familyMemberElder.setFamilyMemberId(userId);
        familyMemberElder.setRemark(dto.getRemark());
        familyMemberElder.setCreateBy(String.valueOf(userId));
        this.save(familyMemberElder);
    }
    /**
     * 查询自己的老人列表
     *
     * @return
     */
    @Override
    public List<MyElderVo> selectMyElder() {
        //1.首先根据用户id查询家属与老人中间表
        Long userId = UserThreadLocal.getUserId();
        List<FamilyMemberElder> familyMemberElderList = this.lambdaQuery().eq(FamilyMemberElder::getFamilyMemberId, userId).list();
        //封装数据
        List<MyElderVo> myElderVoList =new ArrayList<>();
        familyMemberElderList.forEach(x->{

            MyElderVo myElderVo = BeanUtil.toBean(x, MyElderVo.class);
            //获取老人姓名
            Elder elder = elderService.selectElderById(x.getElderId());
            myElderVo.setElderName(elder.getName());
            myElderVoList.add(myElderVo)  ;
        });
        return myElderVoList;
    }
    /**
     * 查询老人列表
     *
     * @return
     */
    @Override
    public List<MyElderListVo> selectElderList() {
        //查询用户id
        Long familyMemberId = UserThreadLocal.getUserId();
        return memberUserMapper.selectElderList(familyMemberId);
    }
    /**
     * 查询健康数据
     * @param dto
     * @return
     */
    @Override
    public Map<String,Object> QueryDevicePropertyStatus(DeviceDto dto) {
        //1.从redis中获得最新设备数据
        List<Object> values = redisTemplate.opsForHash().values(CacheConstants.IOT_DEVICE_DATA_LATEST);
        if (CollUtil.isEmpty(values)) {
            throw new RuntimeException("未找到该老人的设备相关数据");
        }
        //2.将数据转为设备数据集合
        List<DeviceData> deviceDataList=new ArrayList<>();
        for (Object value : values) {
            String deviceDataListJSON = (String) value;
            List<DeviceData> list = JSONUtil.toList(deviceDataListJSON, DeviceData.class);
            deviceDataList.addAll(list);
        }
        //3.找到所需要的设备数据,每个设备的数据根据功能名称是分开的,因为心率要第四个保存,最好把不同功能给分开
        List<DeviceData>dataList =new ArrayList<>();
        for (DeviceData deviceData : deviceDataList) {
            if (deviceData.getDeviceName().equals(dto.getDeviceName())&&deviceData.getProductKey().equals(dto.getProductKey())) {
                dataList.add(deviceData);
            }
        }
        DeviceData HeartRateData =new DeviceData();
        dataList.forEach(x->{
            if ("HeartRate".equals(x.getFunctionId())){
                BeanUtil.copyProperties(x,HeartRateData);
            }
        });
        //4.分开添加各个功能
        PropertyStatusListVO propertyStatusListVO = new PropertyStatusListVO();
        List<PropertyStatusInfoVO> propertyStatusInfoVOList =new ArrayList<>();
        //获得时间戳
        DateTime time = DateUtil.parse(String.valueOf(HeartRateData.getAlarmTime()));
        //获得正确的时间减去八小时
        long updateTime = time.getTime()-28800000;

        //4.1添加BodyTemp
        PropertyStatusInfoVO BodyTemp = new PropertyStatusInfoVO("BodyTemp",String.valueOf(updateTime),"37");
        //4.2添加xueyang
        PropertyStatusInfoVO xueyang = new PropertyStatusInfoVO("xueyang",String.valueOf(updateTime),"140/87");
        //4.3添加BatteryPercentage
        PropertyStatusInfoVO BatteryPercentage = new PropertyStatusInfoVO("BatteryPercentage",String.valueOf(updateTime),"60");
        //4.4添加HeartRate
        PropertyStatusInfoVO  HeartRate = new PropertyStatusInfoVO("HeartRate",String.valueOf(updateTime),HeartRateData.getDataValue());
        //5封装数据
        propertyStatusInfoVOList.add(BodyTemp);
        propertyStatusInfoVOList.add(xueyang);
        propertyStatusInfoVOList.add(BatteryPercentage);
        propertyStatusInfoVOList.add(HeartRate);
        propertyStatusListVO.setPropertyStatusInfo(propertyStatusInfoVOList);
        Map<String,Object> map =new HashMap<>();
        map.put("list",propertyStatusListVO);
        return map;
    }

    /**
     * 按天统计查询指标数据
     *
     * @param dto
     * @return
     */
    @Override
    public List<DataPointVO> QueryDeviceDataListByDay(QueryIoTDataDto dto) {
        //获得指定设备指定功能指定某天的数据
        LocalDateTime startTime = DateUtil.date(dto.getStartTime()).toLocalDateTime();
        LocalDateTime endTime = DateUtil.date(dto.getEndTime()).toLocalDateTime();
        List<DeviceData> deviceData = deviceDataService.lambdaQuery().eq(DeviceData::getIotId, dto.getIotId())
                .eq(DeviceData::getFunctionId, dto.getFunctionId())
                .between(DeviceData::getAlarmTime, startTime, endTime).list();
        // 1. 按小时分组已有数据
        Map<String, List<DeviceData>> collect = deviceData.stream()
                .filter(dp -> dp.getAlarmTime() != null)
                .collect(Collectors.groupingBy(dp ->
                        String.format("%02d:00", dp.getAlarmTime().getHour())
                ));

        // 2. 生成完整的24小时列表，并填充数据（无数据则为0）
        List<DataPointVO> dataPointVOList = new ArrayList<>();
        for (int hour = 0; hour < 24; hour++) {
            String hourKey = String.format("%02d:00", hour);
            List<DeviceData> dataList = collect.getOrDefault(hourKey, Collections.emptyList());
            double avg = 0.0;
            if (!dataList.isEmpty()) {
                avg = dataList.stream()
                        .map(DeviceData::getDataValue)
                        .filter(Objects::nonNull)
                        .mapToDouble(v -> {
                            try {
                                return Double.parseDouble(v);
                            } catch (NumberFormatException e) {
                                return 0.0;
                            }
                        })
                        .average()
                        .orElse(0.0);
            }
            DataPointVO vo = new DataPointVO();
            vo.setDateTime(hourKey);
            vo.setDataValue(Math.floor(avg));
            dataPointVOList.add(vo);
        }
        return dataPointVOList;
    }

    /**
     * 按周统计查询指标数据
     *
     * @param dto
     * @return
     */
    @Override
    public List<DataPointVO> QueryDeviceDataListByWeek(QueryIoTDataDto dto) {
        //获得指定设备指定功能指定某周的数据
        LocalDateTime startTime = DateUtil.date(dto.getStartTime()).toLocalDateTime();
        LocalDateTime endTime = DateUtil.date(dto.getEndTime()).toLocalDateTime();
        List<DeviceData> deviceData = deviceDataService.lambdaQuery().eq(DeviceData::getIotId, dto.getIotId())
                .eq(DeviceData::getFunctionId, dto.getFunctionId())
                .between(DeviceData::getAlarmTime, startTime, endTime).list();
        //按天分组
        Map<String, List<DeviceData>> collect = deviceData.stream()
                .filter(dp -> dp.getAlarmTime() != null)
                .collect(Collectors.groupingBy(dp ->
                        dp.getAlarmTime().format(DateTimeFormatter.ofPattern("MM.dd"))
                ));
        //得到每一天的数据并封装
        // 2. 生成从 startTime 到 endTime 的每一天（按 "MM.dd"），无数据则补 0
        List<DataPointVO> dataPointVOList = new ArrayList<>();
        LocalDate start = startTime.toLocalDate();
        LocalDate end = endTime.toLocalDate();
        for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) {
            String dayKey = date.format(DateTimeFormatter.ofPattern("MM.dd"));
            List<DeviceData> dataList = collect.getOrDefault(dayKey, Collections.emptyList());
            double avg = 0.0;
            if (!dataList.isEmpty()) {
                avg = dataList.stream()
                        .map(DeviceData::getDataValue)
                        .filter(Objects::nonNull)
                        .mapToDouble(v -> {
                            try {
                                return Double.parseDouble(v);
                            } catch (NumberFormatException e) {
                                return 0.0;
                            }
                        })
                        .average()
                        .orElse(0.0);
            }
            DataPointVO vo = new DataPointVO();
            vo.setDateTime(dayKey);
            vo.setDataValue(Math.floor(avg));
            dataPointVOList.add(vo);
        }
        return dataPointVOList;
    }
}
